﻿#region Copyright information
// 
// Copyright © 2005-2013 Yongkee Cho. All rights reserved.
// 
// This code is a part of the Biological Object Library and governed under the terms of the
// GNU Lesser General  Public License (LGPL) version 2.1 which accompanies this distribution.
// For more information on the LGPL, please visit http://bol.codeplex.com/license.
// 
// - Filename: BaroniUrbaniBuser.cs
// - Author: Yongkee Cho
// - Email: yongkeecho@gmail.com
// - Date Created: 2012-09-06 11:39 AM
// - Last Modified: 2013-01-25 3:59 PM
// 
#endregion
using System;
using System.Collections.Generic;
using System.Linq;

namespace BOL.Linq.Distances
{
    public static partial class Similarity
    {
        /// <summary>
        ///                             a + sqrt(ad)
        /// Baroni-Urbani & Buser1 = --------------------
        ///                          a + b + c + sqrt(ad)
        /// </summary>
        public static double BaroniUrbaniBuser1(this IEnumerable<bool> first, IEnumerable<bool> second)
        {
            var bc = first.BinaryCardinality(second);
            var sqAd = Math.Sqrt(bc.Item1 * bc.Item4);

            return (bc.Item1 + sqAd) / (sqAd + bc.Item1 + bc.Item2 + bc.Item3);
        }

        /// <summary>
        ///                          a - b - c + sqrt(ad)
        /// Baroni-Urbani & Buser2 = --------------------
        ///                          a + b + c + sqrt(ad)
        /// </summary>
        public static double BaroniUrbaniBuser2(this IEnumerable<bool> first, IEnumerable<bool> second)
        {
            var bc = first.BinaryCardinality(second);
            var sqAd = Math.Sqrt(bc.Item1 * bc.Item4);

            return (bc.Item1 - bc.Item2 - bc.Item3 + sqAd) / (sqAd + bc.Item1 + bc.Item2 + bc.Item3);
        }

        public static double BaroniUrbaniBuser(this IEnumerable<double> first, IEnumerable<double> second)
        {
            var x = first.ToList();
            var y = second.ToList();

            var maxX = x.Max();
            var minXy = x.Zip(y, Math.Min).Sum();
            var maxXy = x.Zip(y, Math.Max);
            var temp = maxXy.Select(t => maxX - t).Sum();

            return (minXy + Math.Sqrt(minXy * temp)) / (maxXy.Sum() + Math.Sqrt(minXy * temp));
        }
    }
}
